package com.android.lovely.ui.activity

import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.widget.NestedScrollView
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.lifecycleScope
import com.android.lovely.R
import com.android.lovely.const.CreatedImageRefresh
import com.android.lovely.data.AiCreateEvent
import com.android.lovely.data.AiCreateUiEvent
import com.android.lovely.data.GeneratedModel
import com.android.lovely.data.ImageGenerateData
import com.android.lovely.data.ImageGenerationTask
import com.android.lovely.databinding.ActivityAiGenerationBinding
import com.android.lovely.framework.BaseActivity
import com.android.lovely.framework.UIController
import com.android.lovely.framework.UIController.showToast
import com.android.lovely.ui.dialog.CreateImageLoadDialog
import com.android.lovely.ui.dialog.PayDialog
import com.android.lovely.ui.dialog.showLovelyDialog
import com.android.lovely.ui.fragment.image.FaceRetentionView
import com.android.lovely.ui.fragment.image.ModelStyleView
import com.android.lovely.ui.fragment.role.CreateRoleBaseFragment
import com.android.lovely.ui.viewmodel.AiGenerateViewModel
import com.android.lovely.ui.widget.CreateRoleTitleView
import com.android.lovely.user.UserManager
import com.kotlin.extensions.bus.FlowBus
import com.kotlin.extensions.bus.post
import com.kotlin.extensions.context.ContextExt.startPage
import com.kotlin.extensions.context.ContextExt.startPageClearTop
import com.kotlin.extensions.keyboard.KeyboardManager
import com.kotlin.extensions.keyboard.hideKeyboard
import com.kotlin.extensions.view.ViewExt.addStatusBarMarginTop
import com.kotlin.extensions.view.ViewExt.clickable
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

/**
 *
 * @author why
 * @date 2025/4/12 15:41
 */
class AiGenerationActivity : BaseActivity<ActivityAiGenerationBinding>()  {
    val viewModel by viewModels<AiGenerateViewModel>()

    val keyboardManager: KeyboardManager by lazy { KeyboardManager(this) }
    private var followKeyboard: Boolean = true


    override fun initView(savedInstanceState: Bundle?) {
        initViews()
        initObservers()
    }
    private fun initObservers() {
        keyboardManager.setOnKeyboardStateListener {
            onProgress {
                if (!followKeyboard) return@onProgress
                mBinding.clBottom.updateLayoutParams<MarginLayoutParams> { bottomMargin = it }
            }

            onClose {
//                mBinding.edit.clearFocus()
                mBinding.clBottom.updateLayoutParams<MarginLayoutParams> { bottomMargin = 0 }
            }
        }
        lifecycleScope.launch {
            viewModel.createFlow.collectLatest { state ->
                updateUI(state)
            }
        }
        lifecycleScope.launch {
            viewModel.typeFlow.collectLatest { state ->
                updateType(state)
                viewModel.createData.selectedModel = null
                viewModel.createData.currentMode = 0
                viewModel.createData.currentStyle = 0
                updateModeAndStyle()
            }
        }
        lifecycleScope.launch {
            viewModel.genderFlow.collectLatest { state ->
                updateGender(state)
            }
        }
        lifecycleScope.launch {
            viewModel.numFlow.collectLatest { state ->
                updateNum(state)
            }
        }

        lifecycleScope.launch {
            viewModel.updateModel.collectLatest { state ->
//                mBinding.clModelStyle.updateMo
                updateModeAndStyle()
            }
        }
        lifecycleScope.launch {
            viewModel.updateStyle.collectLatest { state ->
                updateModeAndStyle()
            }
        }

        lifecycleScope.launch {
            viewModel.updateNsfw.collectLatest { state ->
                mBinding.imageCreate.refresh(state)
            }
        }
        lifecycleScope.launch {
            viewModel.textPictureMode.collectLatest { state ->
                mBinding.tvPictureSelect.isSelected = state
                mBinding.imageCreate.isVisible = !state
                mBinding.textCreate.isVisible = state

            }
        }


        lifecycleScope.launch {
            viewModel.events.collectLatest { event ->
                handleEvent(event)
            }
        }
        lifecycleScope.launch {
            viewModel.aiWrite.collectLatest { event ->
                mBinding.imageCreate.aiWrite(event)
            }
        }
    }

    private fun handleEvent(event: AiCreateEvent) {
        when (event) {
            is AiCreateEvent.ShowToast -> UIController.showToast(event.message)
            is AiCreateEvent.ShowDialog -> showLovelyDialog {
                setDialogTitle(event.title)
                setDialogMessage(event.message)
                setNegativeButton (getString(R.string.cancel)) {  }
                setPositiveButton (getString(R.string.sure)) { clearAll() }
            }

            AiCreateEvent.NavigateToTask ->
                startPage<CreateWorkActivity>(
                    "task" to true
                )

            AiCreateEvent.ShowLoadDialog -> {
                FlowBus.post(CreatedImageRefresh())
                CreateImageLoadDialog().show(supportFragmentManager)
            }

            AiCreateEvent.ShowPayDialog -> PayDialog().show(supportFragmentManager)
        }
    }


    private fun initViews() {
        mBinding.flTop.addStatusBarMarginTop()
        mBinding.back.clickable {
            finish()
        }
        mBinding.ivRefresh.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnRefresh)
        }
        mBinding.ivHistory.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnMore)
        }
        mBinding.write.clickable {
            showLovelyDialog {
                setDialogTitle(getString(R.string.ai_create_image))
                setNegativeButton (getString(R.string.cancel)) {  }
                setPositiveButton (getString(R.string.sure)) {
                    viewModel.onEvent(AiCreateUiEvent.OnAiWriter(mBinding.roleNsfw.getCheck()))
                }
            }
        }
        mBinding.submit.clickable {
            submit()
        }
        initAge()
        initHeight()
        initType()
        initGender()
        initNSFW()
        initNum()
        initGenerate()
        mBinding.clModelStyle.setListener(object : ModelStyleView.OnModelStyleChang {
            override fun onModeChange(data: GeneratedModel?, position: Int) {
                if (data != null) {
                    viewModel.createData.selectedModel = data
                    viewModel.createData.currentMode = position
                    viewModel.createData.currentStyle = 0
                    viewModel.onEvent(AiCreateUiEvent.OnModelSelected(data, position))
                }
            }

            override fun onStyleChange(data: GeneratedModel?, position: Int) {
                if (data != null) {
                    viewModel.createData.selectedStyle = data
                    viewModel.createData.currentStyle = position
                    viewModel.onEvent(AiCreateUiEvent.OnStyleSelected(data, position))
                }
            }

        })
    }

    private fun submit() {
        hideKeyboard()
        currentFocus?.clearFocus()
//        val uri = faceUri
        //check spend
        val point = UserManager.userInfo?.point ?: 0
        val price = viewModel.createData.createData?.price ?: 0
        val cost = viewModel.createData.currentNum * price

        if (point < cost) {
            showToast(getString(R.string.no_enough_points))
            PayDialog().show(supportFragmentManager)
            return
        }
        //face check
        if(!mBinding.faceContainer.getFragment<FaceRetentionView>().check()) {
            showToast(getString(R.string.generation_no_face))
            mBinding.scroll.smoothScrollTo(0, 0)
            return
        } else {
            viewModel.createData.apply {
                faceUri = mBinding.faceContainer.getFragment<FaceRetentionView>().getUri()
                isFaceOpen = mBinding.faceContainer.getFragment<FaceRetentionView>().getFaceCheck()
            }
        }
        //age check
        val age = mBinding.tvAge.text.toString().toIntOrNull() ?: 0
        if (age < 18) {
            showToast(getString(R.string.age_error))
            mBinding.tvAge.setText(18.toString())
            mBinding.scroll.scrollToTargetView(mBinding.slAgeHeight, false)
            return
        } else if (age > 1000) {
            showToast(getString(R.string.age_error))
            mBinding.tvAge.setText(1000.toString())
            mBinding.scroll.scrollToTargetView(mBinding.slAgeHeight, false)
            return
        } else {
            viewModel.createData.apply {
                this.age = age
            }
        }
        //height check
        val height = mBinding.etHeight.text.toString().toIntOrNull() ?: 0
        if (height < 10) {
            showToast(getString(R.string.height_error))
            mBinding.etHeight.setText(10.toString())
            mBinding.scroll.scrollToTargetView(mBinding.slAgeHeight, false)
            return
        } else if (height > 1000) {
            mBinding.etHeight.setText(1000.toString())
            showToast(getString(R.string.height_error))
            mBinding.scroll.scrollToTargetView(mBinding.slAgeHeight, false)
            return
        } else {
            viewModel.createData.apply {
                this.height = height
            }
        }

        viewModel.createData.apply {
            this.currentGender = if(mBinding.female.isSelected){
                2
            } else if(mBinding.male.isSelected) {
                1
            } else {
                0
            }
            this.currentType = if(mBinding.tvReal.isSelected) 0 else 1
            this.selectedModel = mBinding.clModelStyle.getSelectModel()
            this.selectedStyle = mBinding.clModelStyle.getSelectStyle()
            this.isKeywordMode = mBinding.tvPictureSelect.isSelected
            mBinding.etNumber.text.toString().also { this.currentNum = it.toIntOrNull() ?: 2 }
            this.isNsfwEnabled = mBinding.roleNsfw.getCheck()
        }
        if (!mBinding.tvPictureSelect.isSelected) {
            val item = mBinding.imageCreate.check()
            if (item != null) {
                showToast(
                    getString(
                        R.string.required_not_selected, item.getDetail()?.title
                    )
                )
                mBinding.scroll.scrollToTargetView(item, true)
                return
            } else {
                viewModel.createData.apply {
                    this.imageInput = mBinding.imageCreate.getAllSelected()
                }
            }
        } else {
            val item = mBinding.textContent.text.isNullOrEmpty()
            if (item) {
                showToast(
                    getString(
                        R.string.ai_picture_error
                    )
                )
                mBinding.scroll.scrollToTargetView(mBinding.llTextPictureContent, false)
                return
            } else {
                viewModel.createData.apply {
                    this.textInput =  mBinding.textContent.text.toString()
                }
            }
        }

        viewModel.onEvent(AiCreateUiEvent.OnSubmit)
    }

    private fun initAge() {
        mBinding.tvAge.setText("18")
        mBinding.tvAge.setOnFocusChangeListener { _, hasFocus ->
            if (!hasFocus) {
                val value = mBinding.tvAge.text.toString().toIntOrNull() ?: 0
                if (value < 18) {
                    UIController.showToast(getString(R.string.age_error))
                    mBinding.tvAge.setText("18")
                } else if (value > 1000) {
                    UIController.showToast(getString(R.string.age_error))
                    mBinding.tvAge.setText("1000")
                }
            }
        }
    }

    private fun initHeight() {
        mBinding.etHeight.setText("168")
        mBinding.etHeight.setOnFocusChangeListener { _, hasFocus ->
            if (!hasFocus) {
                val value = mBinding.etHeight.text.toString().toIntOrNull() ?: 0
                if (value < 10) {
                    UIController.showToast(getString(R.string.height_error))
                    mBinding.etHeight.setText("10")
                } else if (value > 1000) {
                    UIController.showToast(getString(R.string.height_error))
                    mBinding.etHeight.setText("1000")
                }
            }
        }
    }

    private fun initType() {
        mBinding.tvReal.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnTypeSelected(0))
        }
        mBinding.tvFantasy.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnTypeSelected(1))
        }
    }

    private fun initGender() {
        mBinding.male.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnGenderSelected(1))
        }
        mBinding.female.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnGenderSelected(2))
        }
        mBinding.unknown.clickable {
            viewModel.onEvent(AiCreateUiEvent.OnGenderSelected(0))
        }
    }

    private fun initNSFW() {
        mBinding.roleNsfw.isVisible = !UserManager.isC()
        mBinding.roleNsfw.changeSwitch(UserManager.isB())
        mBinding.roleNsfw.addCallback(object : CreateRoleTitleView.OnTitleClickListener {
            override fun onSelect(isOpen: Boolean) {
                hideKeyboard()
                viewModel.onEvent(AiCreateUiEvent.OnNsfwChanged(!mBinding.roleNsfw.getCheck()))
            }
        })
    }

    private fun initNum() {
        mBinding.ivAdd.clickable {
            val current = mBinding.etNumber.text.toString().toIntOrNull() ?: 2
            mBinding.ivAdd.isEnabled = (current + 1) < 4
            mBinding.ivMinus.isEnabled = (current + 1) > 1
            if (current < 4) {
                viewModel.onEvent(AiCreateUiEvent.OnNumChanged(current + 1))
            }
        }

        mBinding.ivMinus.clickable {
            val current = mBinding.etNumber.text.toString().toIntOrNull() ?: 2
            mBinding.ivMinus.isEnabled = (current - 1) > 1
            mBinding.ivAdd.isEnabled = (current - 1) < 4
            if (current > 1) {
                viewModel.onEvent(AiCreateUiEvent.OnNumChanged(current - 1))
            }
        }
    }

    private fun initGenerate() {
        mBinding.llTextPicture.isVisible = UserManager.isB()
        mBinding.imageCreate.isVisible = true
        mBinding.textCreate.isVisible = false
        mBinding.scenarioContentNum.text = getString(R.string._0_300_min_30, 0.toString())
        mBinding.tvPictureSelect.clickable {
            val select = !mBinding.tvPictureSelect.isSelected
            mBinding.tvPictureSelect.isSelected = select
            viewModel.onEvent(AiCreateUiEvent.OnGenerateModeChanged(select))
       }
        mBinding.textContent.addTextChangedListener {
            mBinding.scenarioContentNum.text = getString(R.string._0_300_min_30, it?.length.toString())
        }
    }

    private fun updateUI(state: ImageGenerateData) {
        state?.let { data ->
            updateBuyBtn(data.price)
            updateModeAndStyle()
            updateGenerate()
            handleIntent()

        }
    }

    private fun handleIntent() {
        val bundle = intent.extras ?: return
        val task = bundle.getParcelable<ImageGenerationTask>("task") ?: return
        updateWithTask(task)
    }

    private fun updateWithTask(task: ImageGenerationTask) {
        setAge(task.detail.age)
        setHeight(task.detail.height)
        viewModel.onEvent(AiCreateUiEvent.OnTypeSelected(if (task.style == 0) 0 else 1))
        viewModel.onEvent(AiCreateUiEvent.OnGenderSelected(task.detail.gender))
        viewModel.onEvent(AiCreateUiEvent.OnNumChanged(task.count))
        viewModel.onEvent(
            AiCreateUiEvent.OnNsfwChanged(
                task.detail.isNsfw == "1" && !UserManager.isC()
            )
        )

        mBinding.faceContainer.getFragment<FaceRetentionView>().updateAvatar(
            task.imageUrl,
            task.imageUrl.isNotEmpty()

        )

        if (task.detail.workflowType.contains("pure") && UserManager.isB()) {
            mBinding.textContent.setText(task.detail.prompt)
            viewModel.onEvent(AiCreateUiEvent.OnGenerateModeChanged(true))
        }

        if (!task.detail.workflowType.contains("pure")) {
            mBinding.imageCreate.historyWrite(task.detail.parameters.toMap())
            viewModel.onEvent(AiCreateUiEvent.OnGenerateModeChanged(false))
        }
    }

    private fun updateGender(currentGender: Int) {
        mBinding.female.isSelected = currentGender == 2
        mBinding.male.isSelected = currentGender == 1
        mBinding.unknown.isSelected = currentGender == 0
    }

    private fun updateType(currentType: Int) {
        mBinding.tvReal.isSelected = currentType == 0
        mBinding.tvFantasy.isSelected = currentType == 1
    }

    private fun updateNum(state: Int) {
        mBinding.etNumber.setText(state.toString())
        updateBuyBtn(viewModel.createData?.createData?.price ?: 0)
    }

    private fun updateBuyBtn(price: Int) {
        val price = price * (viewModel.createData?.currentNum ?: 2)
        "($price ${getString(R.string.gems)})".also { mBinding.price.text = it }
    }

    private fun updateModeAndStyle() {
        val state = viewModel.createData
        val models = if (state?.currentType == 0) {
            state.createData?.modelCollections?.realistic ?: emptyList()
        } else {
            state?.createData?.modelCollections?.animated ?: emptyList()
        }
        if (state?.selectedModel == null) {
            state?.selectedModel = models.firstOrNull()
            state?.currentMode = 0
        }
        models.map {
            it.isSelected = it.label == state?.selectedModel?.label
        }
        val styleList = state?.selectedModel?.styleVariations ?: emptyList()
        styleList.mapIndexed() { index, item ->
            item.isSelected = index == state?.currentStyle
        }
        mBinding.clModelStyle.update(models, state?.selectedModel?.styleVariations ?: emptyList())
    }

    private fun updateGenerate() {
        val state = viewModel.createData ?: return
        val list = if (state.isNsfwEnabled) {
            state.createData?.parameterCollections?.nsfwEnabled ?: emptyList()
        } else {
            state.createData?.parameterCollections?.nsfwDisabled ?: emptyList()
        }
        mBinding.imageCreate.initView(state.isNsfwEnabled, list)
    }

    private fun clearAll() {
        clearFaceRetention()
        setAge()
        setHeight()
        clearType()
        clearGender()
        clearNSFW()
        clearNum()
        clearGenerate()
    }

    private fun clearFaceRetention() {
        viewModel.onEvent(AiCreateUiEvent.OnFaceUriChanged(null))
        mBinding.faceContainer.getFragment<FaceRetentionView>().clear()
    }

    private fun setAge(age: String = "18") {
        mBinding.tvAge.setText(age)
    }

    private fun setHeight(height: String = "168") {
        mBinding.etHeight.setText(height)
    }

    private fun clearType() {
        viewModel.onEvent(AiCreateUiEvent.OnTypeSelected(0))
    }

    private fun clearGender() {
        viewModel.onEvent(AiCreateUiEvent.OnGenderSelected(1))
    }

    private fun clearNSFW() {
        mBinding.roleNsfw.isVisible = !UserManager.isC()
        mBinding.roleNsfw.changeSwitch(UserManager.isB())
    }

    private fun clearNum() {
        viewModel.onEvent(AiCreateUiEvent.OnNumChanged(2))
    }

    private fun clearGenerate() {
        mBinding.llTextPicture.isVisible = UserManager.isB()
//        viewModel.onEvent(AiCreateUiEvent.OnGenerateModeChanged(true))
        mBinding.textContent.setText("")
        mBinding.imageCreate.clear()
    }

    private fun NestedScrollView.scrollToTargetView(itemView: View, isBottom: Boolean) {
        val top = if (isBottom) mBinding.llTextPictureContent.top else 0
        val itemTop = top + itemView.top
        smoothScrollTo(0, itemTop)
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (!hasFocus) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                mBinding.scroll.updateLayoutParams<MarginLayoutParams> {
                    bottomMargin = 0
                }
            }
        }
    }

}